﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DALManager;
using MyExceptions;
using System.Collections.ObjectModel;
using DataModels;


namespace BL
{
    public class BLClass
    {
        private static readonly DAL dal = new DAL();

        #region Users
        public User GetUser(String username)
        {
            try
            {
                return dal.GetUser(username);
            }
            catch (UserNotFoundException ex)
            {
                throw ex;
            }
        }

        public bool InsertUser(User user)
        {
            bool Result = false;
            if (GetUser(user.Username) == null)
            {
                Result = dal.InsertUser(user);
            }

            return Result;

        }

        public void UpdateUser(User user)
        {
            dal.UpdateUser(user);
        }

        /// <summary>
        /// BL authentication level
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns>true if authenticated, false otherwise</returns>
        public bool IsUserAuthenticated(string username, string password)
        {
            try
            {
                User user = GetUser(username);
                if (user != null)
                {
                    if (user.Password == password)
                        return true;
                    else
                        return false;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {

                throw ex;
            }

        }

        public bool IsUsernameTaken(string username)
        {
            bool result = false;
            if (GetUser(username) != null) // if its null, user already exists
                result = true;

            return result;

        }

        public void DeleteUserByID(int userID)
        {
            dal.DeleteUserByID(userID);
        }

        public void DeleteUserByUsername(String Username)
        {
            dal.DeleteUserByUsername(Username);
        }

        public User GetUserData(string username)
        {
            return dal.GetUserData(username);
        }

        /// <summary>
        /// get all user types
        /// </summary>
        /// <returns></returns>
        public ObservableCollection<UserType> GetUserTypes()
        {
            List<UserType> modelUserTypes = dal.GetUserTypes();
            return new ObservableCollection<UserType>(modelUserTypes);
        }

        #endregion

        #region action types

        public ObservableCollection<ActionType> GetActionTypes()
        {
            List<ActionType> modelActionTypes = dal.GetActionTypes();
            return new ObservableCollection<ActionType>(modelActionTypes);
        }

        public ObservableCollection<ActionType> GetIncomeActionTypes()
        {
            List<ActionType> modelActionTypes = dal.GetIncomeActionTypes();
            return new ObservableCollection<ActionType>(modelActionTypes);
        }

        public ObservableCollection<ActionType> GetOutcomeActionTypes()
        {
            List<ActionType> modelActionTypes = dal.GetOutcomeActionTypes();
            return new ObservableCollection<ActionType>(modelActionTypes);
        }

        #endregion

        #region  Incomes Outcomes

        public ObservableCollection<Income> GetIncomesForUsers(String user)
        {
            List<Income> modelIncomesList = dal.GetIncomesForUsers(user);
            return new ObservableCollection<Income>(modelIncomesList);
        }

        public ObservableCollection<Outcome> GetOutcomesForUsers(String user)
        {
            List<Outcome> modelOutcomesList = dal.GetOutcomesForUsers(user);
            return new ObservableCollection<Outcome>(modelOutcomesList);
        }

        /// <summary>
        /// server validation of income update or insert
        /// </summary>
        /// <param name="income"></param>
        /// <returns></returns>
        private bool IsIncomeValid(Income income)
        {
            if ((income.Amount > 0) && (!String.IsNullOrWhiteSpace(income.Comment)) && (income.ActionTypeId > 0)
                 && (dal.IsActionOfType("Income", income.ActionTypeId)))
                return true;
            return false;
        }


        /// <summary>
        /// server validation of outcome update or insert
        /// </summary>
        /// <param name="outcome"></param>
        /// <returns></returns>
        private bool IsOutcomeValid(Outcome outcome)
        {
            if ((outcome.Amount > 0) && (!String.IsNullOrWhiteSpace(outcome.Comment)) && (outcome.ActionTypeId > 0)
                    && (dal.IsActionOfType("Outcome", outcome.ActionTypeId)))
                return true;
            return false;
        }

        #region Insert



        public int InsertIncome(Income income)
        {
            if (IsIncomeValid(income))
                return dal.InsertIncome(income);
            else
                throw new IncomeNotValidException("Income does not meet the validation mechanism at server");
        }

        public int InsertOutcome(Outcome outcome)
        {
            if (IsOutcomeValid(outcome))
                return dal.InsertOutcome(outcome);
            else
                throw new OutcomeNotValidException("Outcome does not meet the validation mechanism at server");
        }


        #endregion inserts

        #region update

        public void UpdateIncome(Income income)
        {
            if (IsIncomeValid(income))
                dal.UpdateIncome(income);
            else
                throw new IncomeNotValidException("Income does not meet the validation mechanism at server");
        }

        public void UpdateOutcome(Outcome outcome)
        {
            if (IsOutcomeValid(outcome))
                dal.UpdateOutcome(outcome);
            else
                throw new OutcomeNotValidException("Outcome does not meet the validation mechanism at server");
        }



        #endregion update

        #region Delete

        public void DeleteOutcome(int outcomeID)
        {
            dal.DeleteOutcome(outcomeID);
        }

        public void DeleteIncome(int incomeID)
        {
            dal.DeleteIncome(incomeID);
        }

        #endregion Delete

        #endregion //Incomes Outcomes

        #region reports

        public Double GetTotalIncomeForPeriod(ReportMessage reportMessage)
        {
            Double total = 0;

            List<Income> listIncomes = dal.GetIncomesForUserByDateRange(reportMessage.Username, reportMessage.DateFrom, reportMessage.DateTo);
            foreach (var income in listIncomes)
            {
                total += (Double)income.Amount;
            }

            return total;


        }

        public Double GetTotalOutcomeForPeriod(ReportMessage reportMessage)
        {
            Double total = 0;

            List<Outcome> listOutcomes = dal.GetOutcomesForUserByDateRange(reportMessage.Username, reportMessage.DateFrom, reportMessage.DateTo);
            foreach (var outcome in listOutcomes)
            {
                total += (Double)outcome.Amount;
            }

            return total;
        }

        public Double GetTotalBalanceForPeriod(ReportMessage reportMessage)
        {
            Double totalIncome = GetTotalIncomeForPeriod(reportMessage);
            Double totalOutcome = GetTotalOutcomeForPeriod(reportMessage);
            Double total = totalIncome - totalOutcome;

            return total;

        }

        public IEnumerable<Report> GetIncomesBySections(ReportMessage reportMessage)
        {
            return dal.GetIncomesBySections(reportMessage.Username, reportMessage.DateFrom, reportMessage.DateTo);
        }

        public IEnumerable<Report> GetOutcomesBySections(ReportMessage reportMessage)
        {
            return dal.GetOutcomesBySections(reportMessage.Username, reportMessage.DateFrom, reportMessage.DateTo);
        }

        public ObservableCollection<ReportType> GetReportTypesAvailable()
        {
            ObservableCollection<ReportType> _reportTypeList = new ObservableCollection<ReportType>();

            _reportTypeList.Add(new ReportType(1, "Total Income"));
            _reportTypeList.Add(new ReportType(2, "Total Outcome"));
            _reportTypeList.Add(new ReportType(3, "Balance"));
            _reportTypeList.Add(new ReportType(4, "Get Incomes by Sections"));
            _reportTypeList.Add(new ReportType(5, "Get Outcomes by Sections"));

            return _reportTypeList;

        }
        #endregion

    }
}
